package ac.svn.accesscontrol.io;

import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import ac.notification.event.INotificationListener;
import ac.notification.event.NotificationEvent;
import ac.notification.manager.NotificationRegistrar;
import ac.svn.accesscontrol.manager.SVNInfoManager;
import ac.svn.accesscontrol.store.AccessFile;
import ac.svn.accesscontrol.store.AccessUnit;
import ac.svn.accesscontrol.store.Dictionary;
import ac.svn.accesscontrol.store.ISVNIdentifier;
import ac.svn.accesscontrol.store.ISVNItem;
import ac.svn.accesscontrol.store.SVNGroup;
import ac.svn.accesscontrol.store.SVNLocation;
import ac.svn.accesscontrol.utils.Utility;

public class AccessFileWriter implements INotificationListener ,ISVNIdentifier
{
    private JFileChooser chooser;
    public AccessFileWriter()
    {
	chooser = new JFileChooser();
	chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
	chooser.setMultiSelectionEnabled(false);

	NotificationRegistrar.registerListener(this);

    }

    @Override
    public void receiveEvent(NotificationEvent notificationEvent) 
    {
	if(notificationEvent.getPropertyIdentifier().equals(CMD_SAVE_FILE))
	{
	    SwingUtilities.invokeLater(new Runnable() 
	    {
		@Override
		public void run() 
		{
		    saveAccessFile(false);
		}
	    }); 
	}
	else if(notificationEvent.getPropertyIdentifier().equals(CMD_SAVE_FILE_AS))
	{
	    SwingUtilities.invokeLater(new Runnable() 
	    {
		@Override
		public void run() 
		{
		    saveAccessFile(true);
		}
	    }); 
	}
    }

    private void saveAccessFile(boolean saveAs) 
    {
	Utility.sendNotification(N_ACCESS_SAVING_FILE);
	
	String fileName = getFileName(saveAs);

	//Check if at all file has been ever opened.
	if(null != fileName)
	{
	    try
	    {
		File file = new File(fileName);
		FileWriter fileWriter = new FileWriter(file);

		//Generate Contents
		String contents = generateContents();
		fileWriter.write(contents);
		fileWriter.close();	
		
		Utility.sendNotification(N_ACCESS_FILE_SAVED);
	    }
	    catch(final Exception fe)
	    {
		fe.printStackTrace();
		String message = String.format("Unable to save file due to reason:%s", fe.getMessage());
		JOptionPane.showMessageDialog(null, message,"Save failed!",JOptionPane.ERROR_MESSAGE);
	    }
	}

    }

    private String getFileName(boolean saveAs)
    {
	String filePath = null;

	if(true == saveAs)
	{
	    int selOption = chooser.showSaveDialog(null);
	    if(JFileChooser.APPROVE_OPTION == selOption)
	    {
		String fileName = chooser.getSelectedFile().getName().trim();
		if((null == fileName )||(true == fileName.isEmpty()))
		{
		    JOptionPane.showMessageDialog(null, "No Selection made!","Error",JOptionPane.ERROR_MESSAGE);
		    Utility.sendNotification(N_ACCESS_FILE_SAVE_ABORTED);
		}
		else
		{
		    filePath = chooser.getSelectedFile().getAbsolutePath();
		}
	    }
	    else
	    {
		JOptionPane.showMessageDialog(null, "No Selection made!","Error",JOptionPane.ERROR_MESSAGE);
		Utility.sendNotification(N_ACCESS_FILE_SAVE_ABORTED);	
	    }
	}
	else
	{
	    AccessFile  accessFile = Dictionary.getDictionary().getLastAccessFile();
	    //Check if at all file has been ever opened.
	    if(null == accessFile)
	    {
		filePath = getFileName(false);
	    }
	    else
	    {
		filePath = accessFile.getAccessFileLocation();
	    }
	}

	return filePath;
    }




    private String generateContents()
    {
	Utility.sendNotification(N_ACCESS_GENERATING_CONTENTS);	
	
	//Get SVNInformanager.
	SVNInfoManager  svnInfMgr = SVNInfoManager.getInfoManager();

	//Buffer for final file
	StringBuffer stringBuffer = new StringBuffer();

	//Generate contents.
	stringBuffer.append("#Generated on " + (new Date()).toString() + "\n");
	stringBuffer.append("[groups]\n");

	List<SVNGroup> allGroups = new ArrayList<SVNGroup>();

	for(ISVNItem item : svnInfMgr.getAllGroups())
	{
	    SVNGroup  svnGroup = (SVNGroup) item;
	    allGroups.add(svnGroup);
	}

	//Sort By group name
	Collections	.sort(allGroups);

	for(SVNGroup svnGroup : allGroups)
	{
	    String groupTag = "";

	    String header = svnGroup.getComments();

	    String userList = svnGroup.getGroupMembers().toString();
	    userList = userList.replace("["," ");
	    userList = userList.replace("]"," ");
	    userList = userList.trim();


	    if((null != header) && (false == header.trim().isEmpty()))
	    {
		//Make sure new line is added after comment.
		if(false == header.endsWith("\n"))
		{
		    header+="\n";
		}
		groupTag = String.format("\n%s%s=%s\n",header,svnGroup.getGroupAlias(),userList);
	    }
	    else
	    {
		groupTag = String.format("%s=%s\n",svnGroup.getGroupAlias(),userList);
	    }
	    stringBuffer.append(groupTag);
	}

	stringBuffer.append("\n\n");

	for(ISVNItem item : svnInfMgr.getAllLocations())
	{
	    SVNLocation svnLocation = (SVNLocation) item;
	    String locationHeader = svnLocation.getComments();

	    if(null == locationHeader)
	    {
		locationHeader = "";
	    }

	    StringBuffer locationTag = new StringBuffer(String.format("%s[%s]\n",locationHeader,svnLocation.getLocationPath()));
	    for(String  accessUnitId : svnLocation.getAccessUnits())
	    {
		AccessUnit accessUnit = svnInfMgr.getAccessUnit(accessUnitId);
		String header = accessUnit.getComments();

		if(null == header)
		{
		    header = "";
		}

		String prefix = "";
		if(svnInfMgr.isAGroup(accessUnit.getOwnerId()))
		{
		    prefix = "@";
		}

		String strAccessUnit = String.format("%s%s%s = %s\n",header,prefix,accessUnit.getOwnerId(),accessUnit.getAccessAsString());
		locationTag.append(strAccessUnit);									
	    }
	    stringBuffer.append(locationTag + "\n");
	}

	return stringBuffer.toString();
    }

    @Override
    public Set<String> declaredSubscriptionSet() 
    {
	Set<String> subscriptions = new HashSet<String>();
	subscriptions.add(CMD_SAVE_FILE);
	subscriptions.add(CMD_SAVE_FILE_AS);
	return subscriptions;
    }

}
